package com.leetcode.basic.synchronize.ReentrantLock;

import org.junit.Test;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

import static com.leetcode.utils.ThreadUtils.sleep;

public class ReentrantDemo {

	ReentrantLock lock = new ReentrantLock();

	@Test
	public void test() {
		lock.lock();
		System.out.println(getThreadName() + " 获得锁");

		// 开一条线程再获取锁
		new Thread(new Run(500)).start();

		sleep(100);

		System.out.println(getThreadName() + " 释放锁");
		lock.unlock();
	}

	@Test
	public void tryLock() throws InterruptedException {
		// 锁已被线程获取，sleep 500ms后，释放锁
		new Thread(new Run(500)).start();

		// 保证线程启动了
		sleep(1);

		boolean tryLock = lock.tryLock();

		if (!tryLock) {
			System.err.println(getThreadName() + " tryLock()获取锁失败");
		}

		tryLock = lock.tryLock(100, TimeUnit.MILLISECONDS);

		// 100ms内，锁还未被释放，不能获取锁
		if (!tryLock) {
			System.err.println(getThreadName() + " tryLock(100, TimeUnit.SECONDS)获取锁失败");
		}

		// 尝试用1秒获取锁
		tryLock = lock.tryLock(1, TimeUnit.SECONDS);

		// 1秒内，锁已被释放，能获得锁
		if (tryLock) {
			System.out.println(getThreadName() + " tryLock(1, TimeUnit.SECONDS)获得锁");
		}
	}

	class Run implements Runnable {

		long time;

		/**
		 * @param sleepTime 获得锁后，sleep时间
		 */
		public Run(long sleepTime) {
			this.time = sleepTime;
		}

		@Override
		public void run() {
			lock.tryLock();

			if (lock.isHeldByCurrentThread()) {
				System.out.println(getThreadName() + " 获得锁");

				sleep(time);

				lock.unlock();
				System.out.println(getThreadName() + " 释放锁");
			} else {
				System.err.println(getThreadName() + " 获取锁失败");
			}
		}
	}

	/////////////////////////////////////////////

	private String getThreadName() {
		return "线程" + Thread.currentThread().getId();
	}
}
